from ast import main
import json
import time
from tkinter.tix import MAIN
import requests
from datetime import datetime
from datetime import timedelta
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_PKCS1_v1_5
from base64 import b64decode, b64encode
from multiprocessing.dummy import Pool as ThreadPool


# 获取次日日期
def get_resvTime():
    return (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d")


# 记录日志
def log(msg, date, name, chair, usetime):
    f = open("Log_appointment.txt", "a", encoding="utf8")
    f.write(str(date)[:-4] + "\t" + name + "\t" + str(chair) + "\t")
    print(str(date)[:-4] + "\t" + name + "\t" + str(chair) + "\t", end="")
    if (msg["code"] == 1):
        f.write("失败" + "\t" + "用时: " + usetime + "\t" + msg["message"] + "\n")
        print("失败" + "\t" + "用时: " + usetime + "\t" + msg["message"] + "\n", end="")
    elif (msg["code"] == 0):
        f.write("成功" + "\t" + "用时: " + usetime + "\n")
        print("成功" + "\t" + "用时: " + usetime + "\n", end="")
    f.close()


# 获取cookie和RSA加密的密码
# 密码前端加密：格式[密码;nonceStr],加密[固定公钥的RSA加密]
def get_cookie_pwdrsa(password):
    url = "http://zwyylib.ncut.edu.cn/ic-web/login/publicKey"
    response = requests.get(url)

    # 获取Cookie，RSA公钥(其实是固定的)，nonceStr每次变化
    cookie = response.headers.get("Set-Cookie").split(";")[0]
    content = dict(json.loads(response.text)["data"])
    publicKey = content["publicKey"]
    nonceStr = content["nonceStr"]
    msg = password+";"+nonceStr

    # RSA加密
    keyDER = b64decode(publicKey)
    keyPub = RSA.importKey(keyDER)
    cipher = Cipher_PKCS1_v1_5.new(keyPub)
    cipher_text = cipher.encrypt(msg.encode())
    password_rsa = b64encode(cipher_text).decode("utf8")
    return cookie, password_rsa


# 登录
def login(stdid, password):
    cookie, pwdrsa = get_cookie_pwdrsa(password)
    headers = {
        "Host": "zwyylib.ncut.edu.cn",
        "Accept": "application/json, text/plain, */*",
        "lan": "1",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
        "Content-Type": "application/json;charset=UTF-8",
        "Origin": "http://zwyylib.ncut.edu.cn",
        "Referer": "http://zwyylib.ncut.edu.cn/",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cookie": "",
        "Connection": "close"
    }

    data = {
        "logonName": "",
        "password": "",
        "captcha": "",
        "consoleType": 16
    }
    headers["Cookie"] = cookie
    data["logonName"] = stdid
    data["password"] = pwdrsa
    url = "http://zwyylib.ncut.edu.cn/ic-web/login/user"
    response = requests.post(url, headers=headers, data=json.dumps(data))
    js = json.loads(response.text)
    return js["data"]["uuid"], js["data"]["accNo"], cookie


# 预定
# 参数：姓名，学号，密码，座位号，预约开始时间，预约结束时间
# 座位号为累计形式，2楼座位号需加1楼座位总数，依次类推。
def reserve(name, stdid, password, seatNum, BeginTime, EndTime, revother, start, end):
    date = datetime.now()
    start_time = time.perf_counter()
    token, accNo, cookie = login(stdid, password)
    headers = {
        "Host": "zwyylib.ncut.edu.cn",
        "Content-Length": "210",
        "Accept": "application/json, text/plain, */*",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
        "lan": "1",
        "token": "",
        "Content-Type": "application/json;charset=UTF-8",
        "Origin": "http://zwyylib.ncut.edu.cn",
        "Referer": "http://zwyylib.ncut.edu.cn/",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cookie": "",
        "Connection": "close"
    }

    data = {
        "sysKind": 8,
        "appAccNo": 0,
        "memberKind": 1,
        "resvMember": [],
        "resvBeginTime": "",
        "resvEndTime": "",
        "testName": "",
        "captcha": "",
        "resvProperty": 0,
        "resvDev": [],
        "memo": ""
    }

    url = "http://zwyylib.ncut.edu.cn/ic-web/reserve"
    headers["token"] = token
    headers["Cookie"] = cookie
    data["appAccNo"] = int(accNo)
    data["resvMember"] = [int(accNo)]
    data["resvDev"] = [seatNum]
    data["resvBeginTime"] = BeginTime
    data["resvEndTime"] = EndTime

    response = requests.post(url, data=json.dumps(data), headers=headers, timeout=60)
    end_time = time.perf_counter()
    msg = response.json()
    log(msg, date, name, data["resvDev"], format(round(end_time-start_time, 3), '.3f'))
    if (msg["code"] == 1 and revother == True and msg["message"][-7:] != "当前时段有预约"):
        if (msg["message"] == "设备在该时间段内已被预约"):
            for i in range(start, end+1):
                data["resvDev"] = [i]
                date = datetime.now()
                start_time = time.perf_counter()
                response = requests.post(url, data=json.dumps(data), headers=headers, timeout=60)
                end_time = time.perf_counter()
                msg = response.json()
                log(msg, date, name, data["resvDev"], format(round(end_time-start_time, 3), '.3f'))
                if (msg["code"] == 0):
                    break
        else:
            count = 0
            while (True):
                data["resvDev"] = [seatNum]
                date = datetime.now()
                start_time = time.perf_counter()
                response = requests.post(url, data=json.dumps(data), headers=headers, timeout=60)
                end_time = time.perf_counter()
                msg = response.json()
                log(msg, date, name, data["resvDev"], format(round(end_time-start_time, 3), '.3f'))
                count += 1
                if (count >= 10):
                    time.sleep(1)
                    count = 0
                if (msg["code"] == 0):
                    break


# 多线程的调用函数
def run(i):
    reserve(i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7], i[8])


# 仅需要更改此处
info = [
    # 姓名，学号，密码，座位号，预定开始时间（默认为次日），预定结束时间（默认为次日），座位被占是否预约其他位置，其他位置范围
    ["刘瑞斌", "19151xxxxxx", "NCUTxxxxxx", 220, get_resvTime() + " 08:01:00", get_resvTime() + " 20:01:00", True, 90, 336],
    ["王KB", "19151xxxxxx", "NCUTxxxxxx", 220, get_resvTime() + " 08:01:00", get_resvTime() + " 20:01:00", True, 90, 336]
]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# tips：1、预约座位号范围：1楼 1~336 2楼 337~461 3楼 462~769 4楼 770~1369 5楼 1370~1639 6楼 1340~1909 7楼 1910~2059                   #  
#       2、如果想预约的座位为几个不连续座位，则可设置多个列表项，并关闭【座位被占是否预约其他位置】，如想预约1 20 45号座位：               #
#         ["刘瑞斌", "19151xxxxxx", "NCUTxxxxxx", 220, get_resvTime() + " 08:01:00", get_resvTime() + " 20:01:00", True, 90, 336],  #
#         ["刘瑞斌", "19151xxxxxx", "NCUTxxxxxx", 220, get_resvTime() + " 08:01:00", get_resvTime() + " 20:01:00", True, 90, 336],  #
#         ["刘瑞斌", "19151xxxxxx", "NCUTxxxxxx", 220, get_resvTime() + " 08:01:00", get_resvTime() + " 20:01:00", True, 90, 336]   #
#       3、预定开始的日期默认为次日，如果想预约其他日期则可手动输入，但是要注意可预约的时间段，如2022年11月22日：                         #
#         ["刘瑞斌", "19151xxxxxx", "NCUTxxxxxx", 1, "2022-11-22 08:01:00", "2022-11-22 20:01:00", False, 90, 336]                  #
#       4、最后三个参数：True, 90, 336                                                                                               #
#          表示当所预设座位被其他人占后，是否预约其他的座位，True为是，False为否。                                                      #
#          后面表示预约其他座位的范围，90,336则表示从90号座位到336号座位顺序遍历，直到预约到座位。                                       #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

